"""
__author__ = Zdenek Maxa

TODO:
locally fails due to impossibility to run grid authentication chain ...

HAVE NOT BEEN UPDATED FOR A WHILE ...

py.test unittest testing the whole transfer chain locally

test fails if run with 'py.test transfer.py' caused by
py.test bug with combination with multiprocessing
details here (related), not fixed in py.lib 1.2.1
http://bitbucket.org/hpk42/py-trunk/issue/18/pytest-fails-to-coexist-with

keep the name like this so that it's not automatically picked by
running py.test in the directory, should be run separately with -s

TestAction actually fails with
    "FDTCopyException: Call to remote PYRO FDTD service timed-out (firewall in between?)"
    because the FDTD instance running as a process via multiprocessing didn't
    actually started due to:
    Process Process-1:
    Traceback (most recent call last):
    File "/usr/lib/python2.6/multiprocessing/process.py", line 223, in _bootstrap
    sys.stdin.close()
    AttributeError: DontReadFromInput instance has no attribute 'close'

test runs with with 'py.test transfer.py -s' which doesn't capture stdout
"""


import os
import sys
import tempfile
import logging
    
import time
import signal
import filecmp

import py.test
from multiprocessing import Process
from mock import Mock

# tests are in a separate directory, need to make project directory available
baseDir = os.path.abspath(__file__).rsplit(os.sep, 2)[0]
sys.path.append(baseDir)


from fdtcp import TransferFile
from fdtcp import Transfer
from fdtcp import Transfers
from fdtcp import ConfigFDTCopy
from fdtd import ConfigFDTD
from fdtd import FDTD
from common.errors import FDTDException
from common.errors import FDTCopyException
from common.errors import ServiceShutdownBySignal
from utils.Logger import Logger



def setup_module():
    print "this is setup"


def teardown_module():
    global baseDir
    print "this is teardown"
    sys.path.remove(baseDir)
    
        
    
def testWholeTransferChain():    
    logger = Logger("test logger", level = logging.DEBUG)    
    # create FDTD services running locally
    processes = []
    transfers = None
    try:
        inputOptions = "-d DEBUG -p 6700"
        conf = ConfigFDTD(inputOptions.split())
        conf.sanitize()     
        daemon = FDTD(conf, logger)
        p = Process(target = daemon.start)
        p.start()
        processes.append((p, daemon))
    
        inputOptions = "-d DEBUG -p 6701"
        conf = ConfigFDTD(inputOptions.split())
        conf.sanitize()
        daemon = FDTD(conf, logger)
        p = Process(target = daemon.start)
        p.start()
        processes.append((p, daemon))

        fileContent = "my data"
        f = open("/tmp/myfile1", 'w')
        f.write(fileContent)
        f.close()

        # run fdtdcp now
        conf = ConfigFDTCopy("-p 6700 -P 6701 localhost:/tmp/myfile1 localhost:/tmp/myfileA".split())
        conf.sanitize()
        transfers = Transfers(conf, logger)
        t = transfers.transfers["localhostlocalhost"]
        assert len(t.toCleanup) == 0
        
        # actual transfer (tested that finally clause is run fine and gracefully if this fails)
        t.performTransfer()
        
        # URIs to clean up should have been added
        assert len(t.toCleanup) == 2
        
        # compare the files and contents
        assert filecmp.cmp("/tmp/myfile1", "/tmp/myfileA")
        
        d = open("/tmp/myfileA", 'r').read()
        assert d == fileContent        
        
    finally:
        # test if the objects exists - might not have been created
        if transfers:
            for t in transfers.transfers.values():
                t.performCleanup()
                
                # client side ...
                # check if the actual FDTCopy attribute exists - might have failed while creating it
                if t.sender:
                    t.sender.proxy._release()
                if t.receiver:
                    t.receiver.proxy._release()
        
        # after clean up actions - stop daemons / services
        for p, daemon in processes:
            daemon.shutdown() # shutdown the service first
            print "send the FDTD signal to terminate ... will raise ServiceShutdownBySignal ..."
            p.terminate() # will send SIGTERM (rather than doing os.kill(p.pid, signal.SIGTERM) 
            print "running process FDTD (join) ..."
            p.join() # terminated the wrapping process in this test